package org.example.service.order;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.example.dao.entity.order.OOrder;
import org.example.dao.dao.order.OOrderDao;
import org.example.dao.dao.user.UAddressDao;
import org.example.dao.dto.market.StoreDto;
import org.example.dao.dto.order.*;
import org.example.dao.dto.user.UserDto;
import org.example.dao.entity.market.CCommodity;
import org.example.dao.entity.user.UAddress;
import org.example.exception.ParamLossErrorException;
import org.example.exception.ServerErrorException;
import org.example.service.market.CommodityService;
import org.example.service.market.StoreService;
import org.example.skytool.wechat.WechatConstant;
import org.example.skytool.wechat.pay.WxPayResult;
import org.example.skytool.commom.ContextUtil;
import org.example.skytool.commom.IdWorker;
import org.example.skytool.wechat.pay.WechatPayUtil;
import org.example.utils.order.OrderConstant;
import org.example.utils.order.RedisOrderService;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
public class OrderService {


    @Resource
    private OOrderDao oOrderDao;

    @Resource
    private IdWorker idWorker;

    @Resource
    private WechatPayUtil wechatPayUtil;

    @Resource
    private ContextUtil contextUtil;

    @Resource
    private RedisOrderService redisOrderService;

    @Resource
    private StoreService storeService;

    @Resource
    private CommodityService commodityService;


    public OrderDto prepareOrder(HashMap<Long, Integer> map) {
        //根据orders中的commodity ids 获取 commodity列表 而不是每次都查询一次
        List<Long> ids = new ArrayList<>(map.keySet());
        //获取到的commodity列表
        List<CCommodity> list = commodityService.getCommodityByIds(ids);
        //返回result
        OrderDto orderDto = new OrderDto();
        //临时订单号
        String tempTradeNo = idWorker.nextId().toString();
        Long totalCount = 0L;
        Integer totalPrice = 0;
        //商铺hashmap key 商店id value 商品bean
        HashMap<Long, List<OrderCommodity>> map1 = new HashMap<>();
        for (CCommodity commodityDto : list) {
            //将commodityDto转换为我需要的OrderCommodity
            OrderCommodity orderCommodity = new OrderCommodity(commodityDto);
            Integer commodityNum = map.get(commodityDto.getId());
            orderCommodity.setNum(commodityNum);
            //获取商品的商铺id
            Long storeId = orderCommodity.getCommodity().getStoreId();
            if (!map1.containsKey(storeId)) {
                //新建id放入
                map1.put(storeId, new ArrayList<>());
            }
            //放入已有的里面
            map1.get(storeId).add(orderCommodity);
            //记录商品总件数
            totalCount += commodityNum;
            //记录商品总价格
            Long temp = orderCommodity.getCommodity().getCost() * commodityNum;
            totalPrice += Integer.valueOf(temp.toString());
        }
        //根据map中的商铺id，获取商铺list
        ids = new ArrayList<>(map1.keySet());
        List<StoreDto> list1 = storeService.getScoreDtoByIds(ids);
        //把map中的商店id转换为商店
        List<OrderStore> list2 = new ArrayList<>();
        for (StoreDto storeDto : list1) {
            OrderStore orderStore = new OrderStore(storeDto);
            Long storeId = storeDto.getId();
            orderStore.setCommodityList(map1.get(storeId));
            list2.add(orderStore);
        }
        //构造入dto
        orderDto.setTotalNum(totalCount);
        orderDto.setTotalPrice(totalPrice);
        orderDto.setCommodityList(list2);
        orderDto.setAddress(null);
        orderDto.setTempTradeNo(tempTradeNo);
        //将此dto加入缓存 5min
        redisOrderService.setEnsureOrder(tempTradeNo, orderDto);
        return orderDto;
    }


    public OrderWx createOrder(String tempTradeNo, Long addressId) {
        //在redis中查找临时tradeNo
        OrderDto orderDto = redisOrderService.getEnsureOrder(tempTradeNo);
        if (orderDto == null) {
            //找不到 报错 要求用户重新下单 5min内确认
            throw new ParamLossErrorException("请重新下单~注意在五分钟内点击确认下单哦~");
        }
        UserDto userDto = contextUtil.getLoginUser();
        //构造fatherId
        Long fatherId = idWorker.nextId();
        //获取openId
        String openId = userDto.getUser().getOpenId();
        //获取total消费
        Integer total = orderDto.getTotalPrice();
        //构造订单编号（暂时情况，订单编号相同，因为我搞得聚合下单）
        String tradeNo = idWorker.nextId()+"";
        //构造同一时间的下单时间
        Date createTime = new Date();
        Date updateTime = createTime;
        Long userId = contextUtil.getId();
        //取出每一个商品（一个商品买了两个 属于一个商品）
        for (OrderStore orderStore : orderDto.getCommodityList()) {
            for (OrderCommodity orderCommodity : orderStore.getCommodityList()) {
                OOrder order = new OOrder();
                //获取唯一id
                Long id = idWorker.nextId();
                order.setId(id);
                //设置价格
                order.setCost(orderCommodity.getCommodity().getCost() * orderCommodity.getNum());
                //添加fatherid和tradeNo
                order.setFatherId(fatherId);
                order.setTradeNo(tradeNo);
                //添加初始化status
                order.setStatus(OrderConstant.NO_PAY);
                //添加下单时间与更新时间
                order.setCreateTime(createTime);
                order.setUpdateTime(updateTime);
                //添加选择的addressId
                order.setAddressId(addressId);
                //添加商品信息
                order.setCommodityId(orderCommodity.getCommodity().getId());
                order.setCommodityNum(orderCommodity.getNum());
                //添加userId
                order.setUserId(userId);
                //初始化isValid
                order.setIsValid(1);
                //添加入数据库
                oOrderDao.insert(order);
            }
        }
        //从 待确认队列删除
        redisOrderService.delEnsureOrder(tempTradeNo);
        //加入 待支付队列
        redisOrderService.setNoPayOrder(tradeNo);
        //执行微信下单逻辑（）
        String description = "一共买了" + orderDto.getTotalNum() + "个商品";
        WxPayResult result = wechatPayUtil.prepareJsapiOrder(openId, description, total, tradeNo);
        OrderWx orderWx = new OrderWx();
        orderWx.setWxPayResult(result);
        orderWx.setTempTradeNo(tradeNo);
        return orderWx;
    }
    public void finishOrder(String tempTradeNo) {
        //先找到待支付列表中的订单
        Boolean isFlag = redisOrderService.getNoPayOrder(tempTradeNo);
        if(isFlag){
            String status  = wechatPayUtil.queryOrderStatus(tempTradeNo);
            if(status.equals(WechatConstant.SUCCESS)){
                //成功修改库
                redisOrderService.delNoPayOrder(tempTradeNo);
                LambdaQueryWrapper<OOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(OOrder::getIsValid,1);
                lambdaQueryWrapper.eq(OOrder::getTradeNo,tempTradeNo);
                List<OOrder> list = oOrderDao.selectList(lambdaQueryWrapper);
                for(OOrder order : list){
                    order.setStatus(OrderConstant.NO_USE);
                    order.setUpdateTime(new Date());
                    oOrderDao.updateById(order);
                }
            }else if(status.equals(WechatConstant.NOTPAY)){
                //转入 前端确认支付队列
                redisOrderService.delNoPayOrder(tempTradeNo);
                redisOrderService.setPayOrder(tempTradeNo);
            }else if(status.equals(WechatConstant.CLOSED)){
                //删除
                redisOrderService.delNoPayOrder(tempTradeNo);
                //修改表
                LambdaQueryWrapper<OOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(OOrder::getIsValid,1);
                lambdaQueryWrapper.eq(OOrder::getTradeNo,tempTradeNo);
                List<OOrder> list = oOrderDao.selectList(lambdaQueryWrapper);
                for(OOrder order : list){
                    order.setStatus(OrderConstant.CANCEL);
                    order.setUpdateTime(new Date());
                    oOrderDao.updateById(order);
                }
            }else if(status.equals(WechatConstant.USERPAYING)){
                //转入 用户正在支付队列
                redisOrderService.delNoPayOrder(tempTradeNo);
                redisOrderService.setPayingOrder(tempTradeNo);
            }else if (status.equals(WechatConstant.REFUND)){
                //转入退款了 报错 error
                redisOrderService.delNoPayOrder(tempTradeNo);
                throw new ParamLossErrorException("微信订单状态异常");
            }else if (status.equals(WechatConstant.REVOKED)){
                //已撤销 出列
                redisOrderService.delNoPayOrder(tempTradeNo);
            }else if(status.equals(WechatConstant.PAYERROR)){
                //支付出错 报错
                redisOrderService.delNoPayOrder(tempTradeNo);
                throw new ParamLossErrorException("订单已失效，请去订单页刷新订单，或联系管理页");
            }else{
                throw new ServerErrorException("微信订单状态异常");
            }
        }else{
            throw new ParamLossErrorException("订单已失效，请去订单页刷新订单，或联系管理页");
        }








    }

    public  List<OrderListDto> selectOrderByStatus(String status,Integer start,Integer limit) {
        Long userId = contextUtil.getId();
        List<OrderListDto> orderListDtos = oOrderDao.selectOrderDtoByStatus(userId,status,(start-1)*limit,start*limit);
        if(orderListDtos.size()==0){
            return null;
        }
        HashMap<String , OrderListDto> map = new HashMap<>();
        for(OrderListDto orderListDto : orderListDtos){
            map.put(orderListDto.getTradeNo(),orderListDto);
        }
        List<OrderListDto> orderListDtos1 = oOrderDao.selectOrderDtoInTradeNo(new ArrayList(map.keySet()));
       for(OrderListDto orderListDto : orderListDtos1){
            OrderListDto orderListDto1 = map.get(orderListDto.getTradeNo());
           orderListDto1.setStoreList(orderListDto.getStoreList());
           orderListDto1.setCommodityList(orderListDto.getCommodityList());
        }
        return orderListDtos;
    }

    public OrderDto getOrderDetails(String tradeNo) {
        OrderDto orderDto = new OrderDto();
        LambdaQueryWrapper<OOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OOrder::getIsValid,1);
        lambdaQueryWrapper.eq(OOrder::getTradeNo,tradeNo);
        List<OOrder> list = oOrderDao.selectList(lambdaQueryWrapper);
        if(list.size()==0){
            throw new ParamLossErrorException("不存在这样的订单");
        }
        Long addressId = 0L;
        Long totalNum = 0L;
        Integer totalPrice = 0;
        List<Long> commodityIds = new ArrayList<>();
        HashMap<Long, Integer> map = new HashMap<>();
        for(OOrder order : list){
            addressId = order.getAddressId();
            totalNum += order.getCommodityNum();
            totalPrice += Integer.valueOf(order.getCost().toString());
            commodityIds.add(order.getCommodityId());
            map.put(order.getCommodityId(),order.getCommodityNum());
        }
        //获取到的commodity列表
        List<CCommodity> commodityList = commodityService.getCommodityByIds(commodityIds);
        //商铺hashmap key 商店id value 商品bean
        HashMap<Long, List<OrderCommodity>> map1 = new HashMap<>();
        for (CCommodity commodityDto : commodityList) {
            //将commodityDto转换为我需要的OrderCommodity
            OrderCommodity orderCommodity = new OrderCommodity(commodityDto);
            Integer commodityNum = map.get(commodityDto.getId());
            orderCommodity.setNum(commodityNum);
            //获取商品的商铺id
            Long storeId = orderCommodity.getCommodity().getStoreId();
            if (!map1.containsKey(storeId)) {
                //新建id放入
                map1.put(storeId, new ArrayList<>());
            }
            //放入已有的里面
            map1.get(storeId).add(orderCommodity);
        }
        //根据map中的商铺id，获取商铺list
        List<Long> ids = new ArrayList<>(map1.keySet());
        List<StoreDto> list1 = storeService.getScoreDtoByIds(ids);
        //把map中的商店id转换为商店
        List<OrderStore> list2 = new ArrayList<>();
        for (StoreDto storeDto : list1) {
            OrderStore orderStore = new OrderStore(storeDto);
            Long storeId = storeDto.getId();
            orderStore.setCommodityList(map1.get(storeId));
            list2.add(orderStore);
        }
        UAddress address = uAddressDao.selectById(addressId);
        //构造入dto
        orderDto.setTotalNum(totalNum);
        orderDto.setTotalPrice(totalPrice);
        orderDto.setCommodityList(list2);
        orderDto.setAddress(address);
        orderDto.setTempTradeNo(tradeNo);
        return orderDto;
    }

    @Resource
    private UAddressDao uAddressDao;



}
